package main

import (
	"bytes"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"time"
)

var (
	pongWait         = 60 * time.Second
	pingPeriod       = 9 * pongWait / 10
	maxMsgSize int64 = 512
)

var (
	upgrader = websocket.Upgrader{
		HandshakeTimeout: 2 * time.Second,
		ReadBufferSize:   1024,
		WriteBufferSize:  1024,
		WriteBufferPool:  nil,
		Subprotocols:     nil,
		Error:            nil,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
		EnableCompression: false,
	}
)

type Client struct {
	send      chan []byte
	hub       *Hub
	conn      *websocket.Conn
	frontName []byte
}

func (c *Client) read() {
	defer func() {
		c.hub.unregister <- c
		c.conn.Close()
	}()
	c.conn.SetReadLimit(maxMsgSize)
	c.conn.SetReadDeadline(time.Now().Add(pongWait))
	c.conn.SetPongHandler(func(appData string) error {
		c.conn.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})
	for {
		_, msg, err := c.conn.ReadMessage()
		if err != nil {
			fmt.Printf("read from websocket error: %v\n", err)
			break
		}
		// 去除首尾的空格;把换行符替换成空格
		msg = bytes.TrimSpace(bytes.Replace(msg, []byte{'\n'}, []byte{' '}, -1))
		if len(c.frontName) == 0 {
			c.frontName = msg
			log.Printf("%s online\n", string(c.frontName))
		} else {
			c.hub.broadcast <- bytes.Join([][]byte{c.frontName, msg}, []byte(":"))
		}

	}
}

func (c *Client) write() {

	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop() //调用stop，否则协程泄露
		c.conn.Close()
	}()
	for {
		select {
		case msg, ok := <-c.send:
			if !ok { //send管道已关闭
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			} else {
				c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
				//每次new一个writer，是为了确保上一个writer已经关闭，把消息flush给前端
				if writer, err := c.conn.NextWriter(websocket.TextMessage); err != nil {
					return
				} else {
					writer.Write(msg)
					writer.Write([]byte{'\n'}) //追加一个换行符
					n := len(c.send)
					for i := 0; i < n; i++ {
						writer.Write(<-c.send) //从send管道取出消息，写入websocket链接
						writer.Write([]byte{'\n'})
					}
					if writer.Close(); err != nil {
						return
					}
				}
			}
		case <-ticker.C: //发送心跳包
			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				fmt.Printf("ping error: %v\n", err)
				return
			}
		}
	}
}

func ServerWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil) //http升级为websocket协议
	if err != nil {
		fmt.Printf("upgrade http to websocket failed: %v\n", err)
		return
	}
	fmt.Printf("connect to client %s\n", conn.RemoteAddr().String())
	client := &Client{
		send: make(chan []byte, 256),
		hub:  hub,
		conn: conn,
	}
	hub.register <- client //注册client

	go client.read()
	go client.write()

}
